package com.swa99ylum.pjv;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.swa99ylum.pjv.bean.ArrayJSONNode;
import com.swa99ylum.pjv.bean.JSONNode;
import com.swa99ylum.pjv.bean.ObjectJSONNode;
import com.swa99ylum.pjv.util.PJVUtils;
import com.swa99ylum.pjv.validator.FakeValidator;
import com.swa99ylum.pjv.validator.Validator;

public class PluggableJSONValidator extends Component {
	
	private Object rootObject;
	private Map<String, Object[]> nodeFrame;
	private Fuse fuse;
	
	
	@Override
	public String toString() {
		return "PluggableJSONValidator [rootObject=" + rootObject + ", nodeFrame=" + nodeFrame 
				+ ", fuse=" + fuse + "]";
	}


	/**
	 * 将 errorMap 传播到 各个 validator
	 */
	private void spreadErrorHook(Map<String, String> errorMap) {
		
		for(Entry<String, Object[]> entry : nodeFrame.entrySet()) {
			
			Object[] nodes = entry.getValue();
			
			for (Object node : nodes) {
				
				if(node instanceof JSONNode) {
					JSONNode jsonNode = (JSONNode) node;
					
					Validator[] validators = jsonNode.getValidators();
					for (Validator validator : validators) {
						validator.setErrorMap(errorMap);
					}
				}
			}
			
		}
	}
	
	
	public PluggableJSONValidator(String rootStr, Map<String, Object[]> nodeFrame, Fuse fuse, Map<String, String> errorMap) {
		this(JSON.parse(rootStr), nodeFrame, fuse, errorMap);
	}
	
	public PluggableJSONValidator(Object rootObject, Map<String, Object[]> nodeFrame, Fuse fuse, Map<String, String> errorMap) {
		super();
	
		this.rootObject = rootObject;
		
		this.fuse = fuse;
		
		switch (fuse) {
			case ARRAY:
				nodeFrame.put("", new Object[] {new ArrayJSONNode("$")});
				break;
			case OBJECT:
				nodeFrame.put("", new Object[] {new ObjectJSONNode("$")});
				break;
		}
		
		this.nodeFrame = nodeFrame;
		
		
		setErrorMap(errorMap);
		
		spreadErrorHook(errorMap);
	}

	
	public String getRootStrPretty() {
		return JSON.toJSONString(rootObject, SerializerFeature.PrettyFormat);
	}
	
	
	private JSONNode getJSONNode(Object obj) {
		if     (obj instanceof JSONNode)	return ((JSONNode)obj);
		else if(obj instanceof String)		return new JSONNode(String.valueOf(obj));
		else								return null;
	}
	
	/**
	 * 创建一个 "在 errorHook 链 上的" validator
	 */
	private Validator createFakeValidator(String[] nodePath, Object value, String desc) {
		Validator v = new FakeValidator(nodePath, value, desc);
		v.setErrorMap(getErrorMap());
		return v;
	}
	
	public void parse() {
		/* 
		 * 给 rootObject 套一层 "$"
		 * 目的：为了让
		 * 	doParse(rootObject, "$", "$[O]"); 
		 * 	doParse(rootObject, "$", "$[A]");
		 * 也能进入 递归解析 的 流程 
		 */
		Map<String, Object> tmp = new HashMap<String, Object>();
		tmp.put("$", rootObject);
		
		doParse(tmp, new String[]{}, ""); //使用数组 比 使用 List 更加安全，因为 数组 在作为 参数时，不是 引用传递的 
		
	}
	
	@SuppressWarnings("unchecked")
	private void doParse(Object obj, String[] nodePath, String nodeExpression) {
		
		Object[] subNodes = nodeFrame.get(nodeExpression);
			
		for (Object subNode : subNodes) {
			
			JSONNode jsonNode = getJSONNode(subNode);
			if(jsonNode == null) continue;
			
			String subNodeName = jsonNode.getNodeName();
			
			
			String subNodeExpression = "".equals(nodeExpression) ? subNodeName : nodeExpression + "." + subNodeName;
			String[] subNodePath = PJVUtils.append(nodePath, subNodeName);
			
			/*
			long begin = new Date().getTime();
			
			Object currentObj = JSONPath.read(json, subNodePath);
			System.out.println("当前节点：" + subNodePath + " => " + currentObj);
			
			long end = new Date().getTime();
			System.out.println(end-begin);
			*/
			
//			long begin = new Date().getTime();
			//读取 subObj
			Map<String, Object> objMap = (Map<String, Object>)obj;
			Object subObj = objMap.get(subNodeName);
			
//			long end = new Date().getTime();
//			System.out.println("\n\n\n当前节点：" + subNodePath + " => " + subObj + "\n耗时：" + (end-begin) + "\n ===== " + obj);
			
			if(subObj == null) {
				jsonNode.unshiftValidator(createFakeValidator(subNodePath, subObj, "节点 不存在"));
				
				jsonNode.validate(rootObject, subNodePath, subNodeName, objMap, subObj);
				
			}else if(subObj instanceof List) {
				
				if(jsonNode instanceof ObjectJSONNode) // 如果 要求的 类型为 Object
					jsonNode.unshiftValidator(createFakeValidator(subNodePath, subObj, "应当是 Object，不能是 Array"));
				
				
				jsonNode.validate(rootObject, subNodePath, subNodeName, objMap, subObj);
				
				if(nodeFrame.containsKey(subNodeExpression + "[A]")) {
					List<Object> list = (List<Object>) subObj;
					
					for(int i=0; i<=list.size()-1; i++) { 
						//obj = list.get(i); //错误原因：这样会 发生引用覆盖
						Object objEle = list.get(i);
						
						//将 数组的 最后一个元素 改成 带有下标的 值：aaa => aaa[0]
						subNodePath[subNodePath.length-1] = subNodeName + "[" + i + "]";
						
						doParse(objEle, subNodePath, subNodeExpression + "[A]");
						
					}
				}
			}else if(subObj instanceof Map) {
				
				if(jsonNode instanceof ArrayJSONNode) // 如果 要求的 类型为 Array  
					jsonNode.unshiftValidator(createFakeValidator(subNodePath, subObj, "应当是 Array，不能是 Object"));
				

				jsonNode.validate(rootObject, subNodePath, subNodeName, objMap, subObj);
				
				if(nodeFrame.containsKey(subNodeExpression + "[O]")) {//如果 在 nodeFrame 中，nodePath 被开发者 设为是个 Object（即 低下还有 属性）
					
					doParse(subObj, subNodePath, subNodeExpression + "[O]");
				}
				
			} else {
				
				jsonNode.validate(rootObject, subNodePath, subNodeName, objMap, subObj);
//				System.out.println(nodePath + " 没有 子节点 （不是 null、不是 array、不是 object，即 一个 单值属性）");
				
			}
			
		}
		
	}
	
//	public void parse() {
//		doParse("", "");
//	}
//	
//	@SuppressWarnings("unchecked")
//	private void doParse(String nodePath, String nodeExpression) {
//		
//		Object[] subNodes = nodeFrame.get(nodeExpression);
//			
//		for (Object subNode : subNodes) {
//			
//			JSONNode jsonNode = getJSONNode(subNode);
//			if(jsonNode == null) continue;
//			
//			
//			
//			String subNodeName = jsonNode.getNodeName();
//			
//			
//			String subNodeExpression = "".equals(nodeExpression) ? subNodeName : nodeExpression + "." + subNodeName;
//			String subNodePath 		 = "".equals(nodePath	   ) ? subNodeName : nodePath		+ "." + subNodeName;
//			
//			
//			System.out.println("当前节点 => " + subNodePath  + " - " + new Date().getTime());
//			
//			long begin = new Date().getTime();
//			Object obj = JSONPath.read(json, subNodePath);
//			long end = new Date().getTime();
//			System.out.println(end-begin);
//			
//			if(obj == null) {
//				logError(new JSONValidateException(subNodePath, obj, "节点 不存在"));
//				
//				json = jsonNode.validate(json, subNodePath, obj);
//				
//			}else if(obj instanceof List) {// 实际类型 为 Array
//				
//				if(jsonNode instanceof ObjectJSONNode) // 如果 要求的 类型为 Object
//					logError(new JSONValidateException(subNodePath, obj, "应当是 Object，不能是 Array"));
//				
//				
//				json = jsonNode.validate(json, subNodePath, obj);
//				
//				if(nodeFrame.containsKey(subNodeExpression + "[A]")) {
//					List<Object> list = (List<Object>) obj;
//					
//					for(int i=0; i<=list.size()-1; i++) { 
//						
//						doParse(subNodePath+"[" + i + "]", subNodeExpression + "[A]");
//						
//					}
//				}
//				
//			} else if(obj instanceof Map)  {// 实际类型 为 Object
//				
//				if(jsonNode instanceof ArrayJSONNode) // 如果 要求的 类型为 Array  
//					logError(new JSONValidateException(subNodePath, obj, "应当是 Array，不能是 Object"));
//				
//				
//				json = jsonNode.validate(json, subNodePath, obj);
//				
//				
//				if(nodeFrame.containsKey(subNodeExpression + "[O]")) {//如果 在 nodeFrame 中，nodePath 被开发者 设为是个 Object（即 低下还有 属性）
//					doParse(subNodePath, subNodeExpression + "[O]");
//				}
//				
//			} else {
//				
//				json = jsonNode.validate(json, subNodePath, obj);
////				System.out.println(nodePath + " 没有 子节点 （不是 null、不是 array、不是 object，即 一个 单值属性）");
//				
//			}
//			
//		}
//		
//	}


	public Object getRootObject() {
		return rootObject;
	}
	public void setRootObject(Object rootObject) {
		this.rootObject = rootObject;
	}

	public Map<String, Object[]> getNodeFrame() {
		return nodeFrame;
	}
	public void setNodeFrame(Map<String, Object[]> nodeFrame) {
		this.nodeFrame = nodeFrame;
	}

	public Fuse getFuse() {
		return fuse;
	}
	public void setFuse(Fuse fuse) {
		this.fuse = fuse;
	}
	

}
